"use strict";

module.exports = core;

// require：.js/.json/.node
// .js    ->  module.exports/exports
// any    -> .js 去解析
// .json  ->  JSON.parse()
const path = require("path");
const semver = require("semver");
const userHome = require("user-home"); // 用户主目录
const pathExists = require("path-exists").sync;
const { Command } = require("commander");
const exec = require("@test-cli/exec");

const pkg = require("../package.json");
const log = require("@test-cli/log");

const constant = require("./const");

const program = new Command();

let cliConfig = {};

async function core() {
  try {
    prepare();
    registerCommand();
  } catch (e) {
    log.error(e.message);
    if (program.opts().debug) {
      console.log(e);
    }
  }
}

async function prepare() {
  try {
    checkPkgVersion();
    checkRoot();
    checkUserHome();
    checkEnv();
    await checkGlobalUpdate();
  } catch (e) {
    log.error(e.message);
  }
}

// 检查package版本号
function checkPkgVersion() {
  log.info("cli", pkg.version);
}

// 检查root启动
function checkRoot() {
  // 如果是超级管理员，需要进行降权
  // 代码中可能会有很多读写文件的操作，如果是超级管理员创建的文件/文件夹，普通用户会读写失败。
  // 测试方法
  // 默认 sudo test-cli-dev 不进行降权 返回的是 0
  // 使用rootCheck之后执行 sudo test-cli-dev 返回501
  const rootCheck = require("root-check");
  rootCheck();
  // console.log(process.geteuid());
}

// 检查用户主目录
function checkUserHome() {
  if (!userHome || !pathExists(userHome)) {
    throw new Error("当前登录用户主目录不存在！");
  }
}

// 检查环境变量
function checkEnv() {
  const dotenv = require("dotenv");
  const dotenvPath = path.resolve(userHome, ".env.test-cli");
  if (pathExists(dotenvPath)) {
    dotenv.config({
      path: dotenvPath
    });
  }

  createDefaultConfig();
}

// 创建默认配置
function createDefaultConfig() {
  cliConfig.home = userHome;

  cliConfig["cliHome"] = path.join(
    userHome,
    process.env.CLI_HOME || constant.DEFAULT_CLI_HOME
  );

  cliConfig["baseProjectPath"] =
    process.env.CLI_BASE_PROJECT_PATH || constant.DEFAULT_CLI_BASE_PROJECT_PATH;

  cliConfig["targetPath"] = process.env.CLI_TARGET_PATH;

  cliConfig["requestBaseUrl"] =
    process.env.CLI_REQUEST_BASE_URL || constant.DEFAULT_CLI_REQUEST_BASE_URL;

  cliConfig["templateConfigPath"] =
    process.env.CLI_TEMPLATE_CONFIG_PATH ||
    constant.DEFAULT_CLI_TEMPLATE_CONFIG_PATH;

  // 配置路径
  process.env.CLI_HOME_PATH = cliConfig["cliHome"];
  process.env.CLI_BASE_PROJECT_PATH = cliConfig["baseProjectPath"];
  process.env.CLI_TARGET_PATH = cliConfig["targetPath"];
  process.env.CLI_REQUEST_BASE_URL = cliConfig["requestBaseUrl"];
  process.env.CLI_TEMPLATE_CONFIG_PATH = cliConfig["templateConfigPath"];
}

// 检查版本更新
async function checkGlobalUpdate() {
  // 1.获取当前版本号
  // 2.调用npm api，获取所有版本号
  // 3.比对版本号
  // 4.提示用户更新
  const currentVersion = pkg.version;
  const npmName = pkg.name;

  const { getNpmSemverVersions } = require("@test-cli/get-npm-info");
  const lastVersion = await getNpmSemverVersions(currentVersion, npmName);
  if (lastVersion && semver.gt(lastVersion, currentVersion)) {
    log.warn(
      "更新提示",
      `
      请手动更新 ${npmName}, 当前版本: ${currentVersion}, 最新版本: ${lastVersion}
      更新命令: npm i -g ${npmName}
    `
    );
  }
}

// 注册命令
function registerCommand() {
  program
    .name(Object.keys(pkg.bin)[0] + "脚手架")
    .usage("<command> [options]")
    .version(pkg.version)
    .option("-d, --debug", "是否开启调试模式", false)
    .option("-tp, --targetPath <targetPath>", "是否指定本地调试文件路径", "");

  program
    .command("init [projectName]")
    .option("-f --force", "是否强制初始化项目")
    .action(exec);

  // 指定 targetPath 设置环境变量
  program.on("option:targetPath", function () {
    const { targetPath } = this.opts();
    cliConfig.targetPath = targetPath;
    process.env.CLI_TARGET_PATH = targetPath;
  });

  // debug 模式
  program.on("option:debug", function () {
    process.env.LOG_LEVEL = "verbose";
    log.level = process.env.LOG_LEVEL;
    cliConfig.logLevel = process.env.LOG_LEVEL;

    log.verbose("env", cliConfig);
  });

  // 未知命令监听
  program.on("command:*", function (obj) {
    const availableCommands = program.commands.map(cmd => cmd.name());
    log.error(`未知命令：${obj[0]}`);
    if (availableCommands.length) {
      log.error(`可用命令：${availableCommands.join(",")}`);
    }
  });

  program.parse(process.argv);

  if (program.args && program.args.length < 1) {
    program.outputHelp();
    console.log();
  }
}
